#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <omp.h>
#include "fun_group.h"

struct compare
{
    int value;
    int index;
};
#pragma omp declare reduction(maximum          \
                              : struct compare \
                              : omp_out = omp_in.value > omp_out.value ? omp_in : omp_out)
// 声明一个名为maximum的omp reduction，它将使用结构体compare中的值来比较并产生最大值。
// 如果omp_in的值大于omp_out的值，则omp_out的值将被omp_in的值替换。

/**
 * 函数名： parallel_SelectSort
 * 功能：使用OpenMP实现并行排序
 */
void parallel_SelectSort(int *arr, int size)
{
    for (int i = size - 1; i > 0; --i)
    {
        struct compare max;
        max.value = arr[i];
        max.index = i;
        #pragma omp parallel for reduction(maximum \
                                   : max)
        for (int j = i - 1; j >= 0; --j)
        {
            if (arr[j] > max.value)
            {
                max.value = arr[j];
                max.index = j;
            }
        }
        int tmp = arr[i];
        arr[i] = max.value;
        arr[max.index] = tmp;
    }
}

// 主函数
int main()
{
    double parallel_start_time, parallel_end_time, serial_end_time, serial_start_time;

    // 获取数据
    int size_list[11] = {1e3, 1e4, 2e4, 3e4, 4e4, 5e4, 6e4, 7e4, 8e4, 1e5};
    int DataSize = 1e3;
    int proc_num = 12;
    for (int i = 0; i < 11; i++)
    {
        for (int j = 2; j < 13; j++)
        {
            int DataSize = size_list[i]; // set data size
            int proc_num = j;            // set the number of processes
            omp_set_num_threads(proc_num);
            int data[DataSize], dataCopy[DataSize];
            CreateData(data, DataSize);
            for (int i = 0; i < DataSize; ++i)
                dataCopy[i] = data[i];

            // 并行选择排序
            parallel_start_time = omp_get_wtime();
            int n = sizeof(data) / sizeof(int);
            parallel_SelectSort(data, n);
            #pragma omp parallel
            {
                #pragma omp barrier   // 等待所有进程结束
            } parallel_end_time = omp_get_wtime(); // 获取结束时间
            for (int i = 0; i < 100; i++)
            {
                printf("%d ", data[i]);
            }
            puts("");

            // 串行选择排序
            serial_start_time = omp_get_wtime();
            serial_SelectSort(dataCopy, DataSize);
            serial_end_time = omp_get_wtime();

            // 时间分析
            char sort_name[] = "opm_selectsort";
            char filepath[] = "result_select_opm.txt";
            put_time_info(filepath, sort_name, DataSize, proc_num, parallel_start_time, parallel_end_time, serial_start_time, serial_end_time);
        }
    }
    return 0;
}